package com.yuneec.fly.presenters;

import android.content.Context;
import android.os.SystemClock;
import android.os.Vibrator;

import com.yuneec.fly.R;
import com.yuneec.fly.events.EventBusFactory;
import com.yuneec.fly.events.uiEvent.ShowWarningEvent;
import com.yuneec.droneservice.parse.DroneFeedback;

/**
 * Created by zd.zhang on 2016/6/29.
 */
public class WarningPresenter extends BasePresenter {
    private final String gpsDisableWarning;
    private final String gpsLostWarning;
    private final String motorStatusErrorWarming;
    private final String voltageLowWarming1;
    private final String voltageLowWarming2;
    private final String airportWarming;
    private final String altitudeWarming;
    private boolean mLastGPSDisabledWarning = true;
    private Vibrator mVibrator;
    private int currentPriority = 0x0;

    public WarningPresenter(Context context) {
        gpsDisableWarning = context.getString(R.string.str_warning_gps_disabled);
        gpsLostWarning = context.getString(R.string.str_warning_gps_lost);
        motorStatusErrorWarming = context.getString(R.string.str_motor_status_is_error);
        voltageLowWarming1 = context.getString(R.string.str_warning_voltage_low1);
        voltageLowWarming2 = context.getString(R.string.str_warning_voltage_low2);
        airportWarming = context.getString(R.string.str_warning_airport);
        altitudeWarming = context.getString(R.string.str_warning_altitude);
        mLastGPSDisabledWarning = true;
        mVibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
    }

    public void reset() {
        mLastGPSDisabledWarning = true;
        mVibrator.cancel();
        EventBusFactory.getUiBus().post(new ShowWarningEvent(gpsDisableWarning, false));
        EventBusFactory.getUiBus().post(new ShowWarningEvent(gpsLostWarning, false));
        EventBusFactory.getUiBus().post(new ShowWarningEvent(motorStatusErrorWarming, false));
        EventBusFactory.getUiBus().post(new ShowWarningEvent(voltageLowWarming1, false));
        EventBusFactory.getUiBus().post(new ShowWarningEvent(voltageLowWarming2, false));
        EventBusFactory.getUiBus().post(new ShowWarningEvent(airportWarming, false));
        EventBusFactory.getUiBus().post(new ShowWarningEvent(altitudeWarming, false));
    }

    private static final int VOLTAGE_NORMAL = 0x00;
    private static final int VOLTAGE_WARNING1 = 0x01;
    private static final int VOLTAGE_WARNING2 = 0x02;

    private static final int PRIORITY_BATTERY_WARNING2 = 0x4;
    private static final int PRIORITY_GPS_WARNING = 0x2;
    private static final int PRIORITY_BATTERY_WARNING1 = 0x1;

    /**
     * error_flags1
     */
    public static final int ERROR_FLAG_VOLTAGE_WARNING1 = 0x01;
    public static final int ERROR_FLAG_VOLTAGE_WARNING2 = 0x02;
    public static final int ERROR_FLAG_MOTOR_FAILSAFE_MODE = 0x04;
    public static final int ERROR_FLAG_COMPLETE_MOTOR_ESC_FAILURE = 0x08;
    public static final int ERROR_FLAG_HIGH_TEMPERATURE_WARNING = 0x10;
    public static final int ERROR_FLAG_COMPASS_CALIBRATION_WARNING = 0x20;
    public static final int ERROR_FLAG_FLYAWAY_CHECKER_WARNING = 0x40;
    public static final int ERROR_FLAG_AIRPORT_WARNING = 0x80;

    /**
     * VEHICLE_TYPE
     */
    public static final int VEHICLE_TYPE_H920 = 1; // 6 motors
    public static final int VEHICLE_TYPE_Q500 = 2; // 4 motors
    public static final int VEHICLE_TYPE_350QX = 3; // 4 motors
    public static final int VEHICLE_TYPE_380QX = 4; // 4 motors
    public static final int VEHICLE_TYPE_480 = 5; // 6 motors

    public static final int FMODE_BLUE_SOLID = 0;
    public static final int FMODE_BLUE_FLASHING = 1;
    public static final int FMODE_BLUE_WOULD_BE_SOLID_NO_GPS = 2;
    public static final int FMODE_PURPLE_SOLID = 3;
    public static final int FMODE_PURPLE_FLASHING = 4;
    public static final int FMODE_PURPLE_WOULD_BE_SOLID_NO_GPS = 5;
    public static final int FMODE_SMART = 6;
    public static final int FMODE_SMART_BUT_NO_GPS = 7;
    public static final int FMODE_MOTORS_STARTING = 8;
    public static final int FMODE_TEMP_CALIB = 9;
    public static final int FMODE_PRESS_CALIB = 10;
    public static final int FMODE_ACCELBIAS_CALI = 11;
    public static final int FMODE_EMERGENCY_KILLED = 12;
    public static final int FMODE_GO_HOME = 13;
    public static final int FMODE_LANDING = 14;
    public static final int FMODE_BINDING = 15;
    public static final int FMODE_READY_TO_START = 16;
    public static final int FMODE_WAITING_FOR_RC = 17;
    public static final int FMODE_MAG_CALIB = 18;
    public static final int FMODE_RATE = 20;
    public static final int FMODE_FOLLOW = 21;
    public static final int FMODE_FOLLOW_NO_GPS = 22;
    public static final int FMODE_CAMERA_TRACKING = 23;
    public static final int FMODE_CAMERA_TRACKING_NO_GPS = 24;
    private int volFlag = 0;
    private int volFlagIndex = 0;
    private static final int VOL_INDEX_MAX = 15;
    private int[] mVolFlagsArray = {
            -1, -1, -1, -1, -1,
            -1, -1, -1, -1, -1,
            -1, -1, -1, -1, -1
    };
    private int volFlagCurrent = -1;
    private int volFlagEnable = 0;
    private int vibratorFlag = VOLTAGE_NORMAL;

    public void check(DroneFeedback feedback) {
//        checkFlyingStatus(feedback);
        checkFMode(feedback);
        checkVoltageLow(feedback);
        checkGps(feedback);
        checkAirport(feedback);
        checkAltitude(feedback);
    }

    private boolean showFMode = false;
    private boolean showVoltageLow1 = false;
    private boolean showVoltageLow2 = false;
    private boolean showAirport = false;
    private boolean showAltitude = false;

    private void checkFMode(DroneFeedback feedback) {
        int count = 6;
        switch (feedback.vehicleType) {
            case VEHICLE_TYPE_H920:
                count = 6;
                break;
            case VEHICLE_TYPE_350QX:
                count = 4;
                break;
            case VEHICLE_TYPE_Q500:
                count = 4;
                break;
            case VEHICLE_TYPE_380QX:
                count = 4;
                break;
            case 255:
                count = 8;
                break;
        }
        for (int i = 0; i < count; i++) {
            boolean warning = ((feedback.motorStatus >> i) & 0x1) == 0;
            if ((feedback.motorStatus != FMODE_EMERGENCY_KILLED) && warning) {
                if (!showFMode) {
                    showFMode = true;
                    EventBusFactory.getUiBus().post(new ShowWarningEvent(motorStatusErrorWarming, true));
                    startVibrator(PRIORITY_BATTERY_WARNING1);
                }
                return;
            }
        }
        if (showFMode) {
            showFMode = false;
            EventBusFactory.getUiBus().post(new ShowWarningEvent(motorStatusErrorWarming, false));
        }
    }

//    private void checkFlyingStatus(DroneFeedback feedback) {
//        if (!GlobalParams.droneReady) {
//            GlobalParams.droneReady = (feedback.fMode == FMODE_READY_TO_START);
//        }
//        if ((!GlobalParams.droneFlying) && GlobalParams.droneReady && feedback.fMode != FMODE_READY_TO_START) {
//            GlobalParams.droneFlying = true;
//            GlobalParams.droneReady=false;
//        }
//        if (GlobalParams.droneFlying && feedback.fMode == FMODE_READY_TO_START) {
//            GlobalParams.setMissionStaus(GlobalParams.MissionStatus.NONE);
//            GlobalParams.droneFlying = false;
//            GlobalParams.droneReady = true;
//        }
//    }

    private void checkVoltageLow(DroneFeedback feedback) {
        if ((feedback.errorFlags1 & ERROR_FLAG_VOLTAGE_WARNING1) != 0
                && (feedback.errorFlags1 & ERROR_FLAG_VOLTAGE_WARNING2) == 0) {
            // Voltage low warning 1 level flag
            volFlag = VOLTAGE_WARNING1;
        } else if ((feedback.errorFlags1 & ERROR_FLAG_VOLTAGE_WARNING2) != 0) {
            // Voltage low warning 2 level flag
            volFlag = VOLTAGE_WARNING2;
        } else {
            volFlag = VOLTAGE_NORMAL;
        }
        if (volFlagIndex >= VOL_INDEX_MAX) volFlagIndex = 0;
        mVolFlagsArray[volFlagIndex++] = volFlag;
        int i;
        for (i = 0; i < VOL_INDEX_MAX; i++) {
            if (mVolFlagsArray[i] >= 0) {
                if (mVolFlagsArray[i] != volFlag) {
                    volFlagCurrent = -1;
                    break;
                } else {
                    volFlagCurrent = volFlag;
                }
            } else {
                break;
            }
        }
        if ((i == VOL_INDEX_MAX) && (volFlagCurrent >= 0)) {
            volFlagEnable = volFlagCurrent;
        }

        if ((volFlagEnable == VOLTAGE_WARNING1) && (vibratorFlag != VOLTAGE_WARNING1)) {
//            showVoltageLowWarning1();
            vibratorFlag = VOLTAGE_WARNING1;
            EventBusFactory.getUiBus().post(new ShowWarningEvent(voltageLowWarming2, false));
            EventBusFactory.getUiBus().post(new ShowWarningEvent(voltageLowWarming1, true));
            startVibrator(PRIORITY_BATTERY_WARNING1);
            new Thread(new Runnable() {
                @Override
                public void run() {
                    SystemClock.sleep(10000);
                    stopVibrator(PRIORITY_BATTERY_WARNING1);
                }
            }).start();
        } else if ((volFlagEnable == VOLTAGE_WARNING2) && (vibratorFlag != VOLTAGE_WARNING2)) {
//            showVoltageLowWarning2();
            vibratorFlag = VOLTAGE_WARNING2;
            EventBusFactory.getUiBus().post(new ShowWarningEvent(voltageLowWarming1, false));
            EventBusFactory.getUiBus().post(new ShowWarningEvent(voltageLowWarming2, true));
            startVibrator(PRIORITY_BATTERY_WARNING2);
            new Thread(new Runnable() {
                @Override
                public void run() {
                    SystemClock.sleep(10000);
                    stopVibrator(PRIORITY_BATTERY_WARNING2);
                }
            }).start();
        } else if ((volFlagEnable != VOLTAGE_WARNING1) && (volFlagEnable != VOLTAGE_WARNING2)
                && (vibratorFlag != VOLTAGE_NORMAL)) {
            vibratorFlag = VOLTAGE_NORMAL;
            EventBusFactory.getUiBus().post(new ShowWarningEvent(voltageLowWarming1, false));
            EventBusFactory.getUiBus().post(new ShowWarningEvent(voltageLowWarming2, false));
            stopVibrator(PRIORITY_BATTERY_WARNING1);
            stopVibrator(PRIORITY_BATTERY_WARNING2);
        }
    }

    private void checkGps(DroneFeedback feedback) {
        int warningType = 0;
        if (feedback.gpsStatus == 1) {
            if (!feedback.gpsUsed) {
                warningType = 1;    //Lost
            }
        } else {
            if (!feedback.gpsUsed) {
                warningType = 2; //Disabled
            }
        }
        boolean warning = !feedback.gpsUsed;
        boolean changed = (warning != mLastGPSDisabledWarning);
        if (changed) {
            if (warning) {
                if (warningType == 1) {
                    EventBusFactory.getUiBus().post(new ShowWarningEvent(gpsDisableWarning, false));
                    EventBusFactory.getUiBus().post(new ShowWarningEvent(gpsLostWarning, true));
                } else {
                    EventBusFactory.getUiBus().post(new ShowWarningEvent(gpsLostWarning, false));
                    EventBusFactory.getUiBus().post(new ShowWarningEvent(gpsDisableWarning, true));
                }
                startVibrator(PRIORITY_GPS_WARNING);
            } else {
                EventBusFactory.getUiBus().post(new ShowWarningEvent(gpsLostWarning, false));
                EventBusFactory.getUiBus().post(new ShowWarningEvent(gpsDisableWarning, false));
                stopVibrator(PRIORITY_GPS_WARNING);
            }
        }
        mLastGPSDisabledWarning = warning;
    }

    private void checkAltitude(DroneFeedback feedback) {
        if ((feedback.errorFlags1 & ERROR_FLAG_AIRPORT_WARNING) != 0) {
            if (!showAltitude) {
                showAltitude = true;
                EventBusFactory.getUiBus().post(new ShowWarningEvent(airportWarming, true));
            }
        } else {
            if (showAltitude) {
                showAltitude = false;
                EventBusFactory.getUiBus().post(new ShowWarningEvent(airportWarming, false));
            }
        }
    }

    private void checkAirport(DroneFeedback feedback) {
        if ((feedback.errorFlags1 & ERROR_FLAG_MOTOR_FAILSAFE_MODE) != 0) {
            if (!showAirport) {
                showAirport = true;
                EventBusFactory.getUiBus().post(new ShowWarningEvent(altitudeWarming, true));
            }
        } else {
            if (showAirport) {
                showAirport = false;
                EventBusFactory.getUiBus().post(new ShowWarningEvent(altitudeWarming, false));
            }
        }
    }

    private void startVibrator(int priority) {
        if (priority == PRIORITY_BATTERY_WARNING2) {
            if ((currentPriority & PRIORITY_BATTERY_WARNING2) != PRIORITY_BATTERY_WARNING2) {
                mVibrator.cancel();
                mVibrator.vibrate(new long[]{1000, 1000, 1000, 1000}, 0);
            }
            currentPriority |= PRIORITY_BATTERY_WARNING2;
        } else if (priority == PRIORITY_GPS_WARNING) {
            if ((currentPriority & PRIORITY_BATTERY_WARNING2) != PRIORITY_BATTERY_WARNING2
                    && (currentPriority & PRIORITY_GPS_WARNING) != PRIORITY_GPS_WARNING) {
                mVibrator.cancel();
                mVibrator.vibrate(new long[]{1000, 1000, 1000, 1000}, 0);
            }
            currentPriority |= PRIORITY_GPS_WARNING;
        } else {
            if ((currentPriority & PRIORITY_BATTERY_WARNING2) != PRIORITY_BATTERY_WARNING2
                    && (currentPriority & PRIORITY_GPS_WARNING) != PRIORITY_GPS_WARNING
                    && (currentPriority & PRIORITY_BATTERY_WARNING1) != PRIORITY_BATTERY_WARNING1) {
                mVibrator.cancel();
                mVibrator.vibrate(new long[]{1000, 1000, 5000, 1000}, 0);
            }
            currentPriority |= PRIORITY_BATTERY_WARNING1;
        }
    }

    private void stopVibrator(int priority) {
        if ((currentPriority & priority) == 0) {
            return;
        }
        mVibrator.cancel();
        currentPriority &= ~priority;
        if ((currentPriority & PRIORITY_BATTERY_WARNING2) == PRIORITY_BATTERY_WARNING2) {
            mVibrator.vibrate(new long[]{1000, 1000, 1000, 1000}, 0);
        } else if ((currentPriority & PRIORITY_GPS_WARNING) == PRIORITY_GPS_WARNING) {
            mVibrator.vibrate(new long[]{1000, 1000, 1000, 1000}, 0);
        } else if ((currentPriority & PRIORITY_BATTERY_WARNING1) == PRIORITY_BATTERY_WARNING1) {
            mVibrator.vibrate(new long[]{1000, 1000, 5000, 1000}, 0);
        }
    }
}
